﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xml;

namespace Javavaj.iHunter.Core
{
    /// <summary>
    /// 表示频道中一条信息
    /// </summary>
    public sealed class Message : IMessage
    {
        private XmlDocument xml;

        private string this[string name]
        {
            get
            {
                XmlElement node = xml.DocumentElement[name];
                if (node == null)
                    return "";
                else
                    return node.InnerText;//这里应该用InnerText，而不是Value
            }
            set
            {
                XmlElement node = xml.DocumentElement[name];
                if (node == null)
                {
                    xml.DocumentElement.AppendChild(xml.CreateElement(name));
                    node = xml.DocumentElement[name];
                }
                node.InnerText = value;
            }
        }
        /// <summary>
        /// 获取信息的属性集
        /// </summary>

        private void createRootXml()
        {
            xml = new XmlDocument();
            xml.LoadXml("<Message>      " +
                        "   <ChannelHash />   " +
                        "   <Title />   " +
                        "   <Content DocType=\"text\" Binary = \"false\"/>  " +
                        "</Message>     "
            );

        }

        /// <summary>
        /// 创建信息
        /// </summary>
        /// <param name="creator">创建消息的频道对象</param>
        public Message(IChannel creator)
        {
            createRootXml();
            if (creator == null)
                this.ChannelHash = 0;
            else
                this.ChannelHash = creator.GetHashCode();
        }

        #region IMessage Members

        //hc:
        //把ChannelHash直接存在Message的XML文件里了。这样可以保持到序列化以后。
        //先这样，还要看数据库的设计。如果数据库里有ChannelHash的项，这个可以去掉。

        /// <summary>
        /// 消息所属频道的Hash编码
        /// </summary>
        public int ChannelHash
        {
            get
            {
                return int.Parse(this["ChannelHash"]);
            }
            set
            {
                this["ChannelHash"] = value.ToString();
            }
        }
        /// <summary>
        /// 获取或设置信息标题
        /// </summary>

        public string Title
        {
            get
            {
                return this["Title"];
            }
            set
            {
                this["Title"] = value;
            }
        }

        /// <summary>
        /// 获取或设置信息的原始链接地址
        /// </summary>
        public string Link
        {
            get
            {
                return this["Link"];
            }
            set
            {
                this["Link"] = value;
            }
        }

        /// <summary>
        /// 获取或设置信息的描述(摘要)
        /// </summary>
        public string Description
        {
            get
            {
                return this["Description"];
            }
            set
            {
                this["Description"] = value;
            }
        }

        /// <summary>
        /// 获取或设置信息的发布时间
        /// </summary>
        public DateTime PubTime
        {
            get
            {
                //如果没有设置的话，就返回MinValue。没法返回null，DateTime是非nullable。
                if (this["PubTime"].Length == 0)
                    return DateTime.MinValue;
                else
                    return DateTime.Parse(this["PubTime"]);
            }
            set
            {
                this["PubTime"] = value.ToString();
            }
        }

        /// <summary>
        /// 获取或设置信息的最后修改时间
        /// </summary>
        public DateTime LastBuildTime
        {
            get
            {
                if (this["LastBuildTime"].Length == 0)
                    return DateTime.MinValue;
                else
                    return DateTime.Parse(this["PubTime"]);
            }
            set
            {
                this["LastBuildTime"] = value.ToString();
            }
        }

        /// <summary>
        /// 获取或设置信息的最后有效期限
        /// </summary>
        public DateTime DueTime
        {
            get
            {
                if (this["DueTime"].Length == 0)
                    return DateTime.MinValue;
                else
                    return DateTime.Parse(this["DueTime"]);
            }
            set
            {
                this["DueTime"] = value.ToString();
            }
        }

        /// <summary>
        /// 获取或设置信息的作者
        /// </summary>
        public string Author
        {
            get
            {
                return this["Author"];
            }
            set
            {
                this["Author"] = value;
            }
        }

        /// <summary>
        /// 获取或设置信息所属的类别
        /// </summary>
        public string Category
        {
            get
            {
                return this["Category"];
            }
            set
            {
                this["Category"] = value;
            }
        }

        /// <summary>
        /// 获取或设置信息的重要级别
        /// </summary>
        public int Importance
        {
            get
            {
                if (this["Importance"].Length == 0)
                    return 0;
                else
                    return int.Parse(this["Importance"]);
            }
            set
            {
                this["Importance"] = value.ToString();
            }
        }

        /// <summary>
        /// 获取或设置消息是否可以被回复或提交附件
        /// </summary>
        public bool Repliable
        {
            get
            {
                if (this["Repliable"].Length == 0)
                    return false;
                else
                    return bool.Parse(this["Repliable"]);
            }
            set
            {
                this["Repliable"] = value.ToString();
            }
        }


        /// <summary>
        /// 获取或设置信息的附件
        /// </summary>
        /// <returns>返回IFileObject对象的ICollection集合；没有附件则返回null</returns>
        public IList<IFileObject> Attachments
        {
            get
            {
                XmlElement attachments = xml.DocumentElement["Attachments"];
                List<IFileObject> attachmentList = new List<IFileObject>();
                if (attachments != null)
                {
                    foreach (XmlNode node in attachments.ChildNodes)
                    {
                        attachmentList.Add(new Attachment(int.Parse(node.Attributes["Id"].Value),
                                                        node.Attributes["Filename"].Value,
                                                        node.Attributes["FileType"].Value,
                                                        long.Parse(node.Attributes["FileSize"].Value),
                                                        node.Attributes["FileUri"].Value,
                                                        node.Attributes["LocalPath"].Value,
                                                        node.Attributes["Description"].Value)
                                                       );
                    }
                }
                 return attachmentList;
           }
            set
            {
                if (value == null || value.Count == 0)
                {
                    XmlElement attachments = xml.DocumentElement["Attachments"];
                    if (attachments != null)
                        xml.DocumentElement.RemoveChild(attachments);
                }
                else
                {
                    XmlElement newAttachments = xml.CreateElement("Attachments");
                    foreach (IFileObject fo in value)
                    {
                        XmlElement newAttachment = xml.CreateElement("Attachment");
                        XmlAttribute attr = xml.CreateAttribute("Id");
                        attr.Value = fo.Id.ToString();
                        newAttachment.SetAttributeNode(attr);

                        attr = xml.CreateAttribute("Filename");
                        attr.Value = fo.Filename;
                        newAttachment.SetAttributeNode(attr);
   
                        attr = xml.CreateAttribute("FileType");
                        attr.Value = fo.FileType;
                        newAttachment.SetAttributeNode(attr);
            
                        attr = xml.CreateAttribute("FileSize");
                        attr.Value = fo.FileSize.ToString();
                        newAttachment.SetAttributeNode(attr);
                    
                        attr = xml.CreateAttribute("FileUri");
                        attr.Value = fo.FileUri;
                        newAttachment.SetAttributeNode(attr);

                        attr = xml.CreateAttribute("LocalPath");
                        attr.Value = fo.LocalPath;
                        newAttachment.SetAttributeNode(attr);

                        attr = xml.CreateAttribute("Description");
                        attr.Value = fo.Description;
                        newAttachment.SetAttributeNode(attr);

                        newAttachments.AppendChild(newAttachment);
                    }
                    XmlElement oldAttachments = xml.DocumentElement["Attachments"];
                    if (oldAttachments != null)
                    {
                        oldAttachments.RemoveAll();
                        xml.DocumentElement.RemoveChild(oldAttachments);
                    }

                    xml.DocumentElement.AppendChild(newAttachments);

                }
            }
        }

        #endregion

        #region IXmlSerializable Members

        /// <summary>
        /// 获取Xml Sehema
        /// </summary>
        /// <returns></returns>
        public System.Xml.Schema.XmlSchema GetSchema()
        {
            //MSDN里这样规定的
            return null;
        }

        /// <summary>
        /// 从制定的XmlReader读取消息
        /// </summary>
        /// <param name="reader">Xml读取器对象</param>
        public void ReadXml(XmlReader reader)
        {
            xml.Load(reader);
        }

        /// <summary>
        /// 向指定的XmlWriter写入消息内容
        /// </summary>
        /// <param name="writer">Xml写入器对象</param>
        public void WriteXml(XmlWriter writer)
        {
            xml.WriteTo(writer);
        }

        #endregion

        #region IMessage 成员

        /// <summary>
        /// 获取或设置正文的文档类型
        /// </summary>
        public string ContentType
        {
            get
            {
                if (xml.DocumentElement["Content"] == null)
                    return "";
                if (xml.DocumentElement["Content"].Attributes["DocType"] == null)
                    return "text";
                return xml.DocumentElement["Content"].Attributes["DocType"].Value;
            }
            set
            {
                if (xml.DocumentElement["Content"] == null)
                    xml.DocumentElement.AppendChild(xml.CreateElement("Content"));
                if (xml.DocumentElement["Content"].Attributes["DocType"] == null)
                    xml.DocumentElement["Content"].Attributes.Append(xml.CreateAttribute("DocType"));
                xml.DocumentElement["Content"].Attributes["DocType"].Value = value;

            }
        }

        #endregion

        #region IMessage 成员

        /// <summary>
        /// 获取或设置信息的内容
        /// </summary>
        /// <remarks>
        /// 若正文为文本格式(ContentIsBinary为“假”(False)，则返回值为string对象；若正文为二进制格式，返回值为byte[]对象
        /// 在设置该值时，可以接受的对象类型为String, StringBuilder, byte[], 或者类型参数为byte的IList的泛型接口
        /// </remarks>
        public object Content
        {
            get
            {
                if (ContentIsBinary)
                {
                    //                    if (xml.DocumentElement["Content"] == null)
                    //                        return new byte[0];
                    try
                    {
                        return Convert.FromBase64String(xml.DocumentElement["Content"].InnerText);
                    }
                    catch (FormatException)
                    {
                        return new byte[0];
                    }
                }
                else
                {
                    //                   if (xml.DocumentElement["Content"] == null)
                    //                       return "";

                    return xml.DocumentElement["Content"].InnerText;
                }
            }
            set
            {
                if (value == null)
                    throw new ArgumentNullException();

                //                if (xml.DocumentElement["Content"] == null)
                //                    xml.DocumentElement.AppendChild(xml.CreateElement("Content"));

                if (value is string || value is StringBuilder)
                {
                    ContentIsBinary = false;
                    xml.DocumentElement["Content"].InnerText = value.ToString();
                }
                else
                {
                    ContentIsBinary = true;
                    byte[] bytes = value as byte[];
                    if (bytes == null)
                    {

                        bytes = ((IList<byte>)value).ToArray<byte>();
                        if (bytes == null)
                            throw new ArgumentException();
                    }

                    xml.DocumentElement["Content"].InnerText = Convert.ToBase64String(bytes);

                }
            }
        }

        /// <summary>
        /// 获取一个布尔值，表示正文是否为二进制数据
        /// </summary>

        public bool ContentIsBinary
        {
            get
            {
                //               if (xml.DocumentElement["Content"] == null)
                //                   return false;
                //               if (xml.DocumentElement["Content"].Attributes["Binary"] == null)
                //                   return false;
                //               try
                //               {
                return bool.Parse(xml.DocumentElement["Content"].Attributes["Binary"].Value);
                //               }
                //               catch (FormatException)
                //               {
                //                   return false;
                //               }
            }
            private set
            {
                //               if (xml.DocumentElement["Content"] == null)
                //                   xml.DocumentElement.AppendChild(xml.CreateElement("Content"));
                //               if (xml.DocumentElement["Content"].Attributes["Binary"] == null)
                //                   xml.DocumentElement["Content"].Attributes.Append(xml.CreateAttribute("Binary"));

                xml.DocumentElement["Content"].Attributes["Binary"].Value = value.ToString();
            }
        }

        #endregion


        #region IMessage 成员

        public int Id
        {
            get
            {
                if (this["Id"].Length == 0)
                    return 0;
                else
                    return int.Parse(this["Id"]);
            }
            set
            {
                this["Id"] = value.ToString();
            }
        }

        public int Uid
        {
            get
            {
                if (this["Uid"].Length == 0)
                    return 0;
                else
                    return int.Parse(this["Uid"]);
            }
            set
            {
                this["Uid"] = value.ToString();
            }
        }

        public bool Read
        {
            get
            {
                if (this["Read"].Length == 0)
                    return false;
                else
                    return bool.Parse(this["Read"]);
            }
            set
            {
                this["Read"] = value.ToString();
            }
        }

        #endregion

        public override bool Equals(object obj)
        {
            IMessage msg = obj as Message;
            if (obj == null)
                return false;
            else
                return (Equals(msg));
        }

        public bool Equals(Message msg)
        {
            //TODO
            return true;
        }
        public override int GetHashCode()
        {
            return Uid;
        }


        #region IMessage 成员


        public bool Deleted
        {
            get;
            set;
        }

        public bool Spam
        {
            get;
            set;
        }

        #endregion
    }
}